﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Geometry
{
    public partial class LineString
    {
        #region 字段属性
        protected string id;
        protected double length;
        protected Envelope envelope;

        public string ID { get => id; }
        public Point PointFrom { get; set; }
        public Point PointTo { get; set; }
        public List<Point> PointList { get; set; }
        public double Length { get => length; }
        public Envelope Envelope { get => envelope; }
        public List<string> PointIDList { get; set; }

        #endregion

        #region 构造器
        /// <summary>
        /// 点串构造法
        /// </summary>
        /// <param name="points">点集</param>
        public LineString(List<Point> points)
        {
            if (points.Count >= 2)
            {
                envelope = new Envelope();
                PointList = points;
                PointFrom = points[0];
                PointTo = points[points.Count - 1];
                SetLength();
                SetEnvelope();
            }
            else
                Console.WriteLine("线必须要有2个端点！");
        }

        /// <summary>
        /// 点串构造法
        /// </summary>
        /// <param name="id">折线ID</param>
        /// <param name="points">点集</param>
        public LineString(string id, List<Point> points)
        {
            if (points.Count >= 2)
            {
                envelope = new Envelope();
                this.id = id;
                PointList = points;
                PointFrom = points[0];
                PointTo = points[points.Count - 1];
                SetLength();
                SetEnvelope();
            }
            else
                Console.WriteLine("线必须要有2个端点！");
        }

        /// <summary>
        /// 点索引构造法
        /// </summary>
        /// <param name="id">折线ID</param>
        /// <param name="indexType">索引类型</param>
        /// <param name="IDs">ID集合</param>
        public LineString(string id,  params string[] IDs)
        {
            this.id = id;
            PointIDList = new List<string>();
            PointIDList.AddRange(IDs);
        }

        public LineString() { }
        #endregion

        #region 方法
        public void WriteLine()
        {
            Console.Write($"{ID} (");
            for (int i = 0; i < this.PointList.Count; i++)
            {
                if (i != PointList.Count - 1)
                    Console.Write($"{PointList[i].ID},");
                else
                    Console.Write("{0}) {1:#.##}\n",
                        PointList[i].ID, Length);
            }
        }

        public bool Equals(LineString polylineOther)
        {
            if (PointList.Count == polylineOther.PointList.Count)
            {
                for (int i = 0; i < PointList.Count; i++)
                {
                    if (PointList[i] != polylineOther.PointList[i])
                        return false;
                }
                return true;
            }
            return false;
        }

        protected void SetLength()
        {
            length = 0;
            for (int i = 0; i < PointList.Count - 1; i++)
                length += PointList[i].GetDistance(PointList[i + 1]);
        }

        protected void SetEnvelope()
        {
            envelope.XMin = PointList.Min(point => point.X);
            envelope.XMax = PointList.Max(point => point.X);
            envelope.YMin = PointList.Min(point => point.Y);
            envelope.YMax = PointList.Max(point => point.Y);
        }

        /// <summary>
        /// 包围盒内
        /// </summary>
        /// <param name="point">点</param>
        public bool IsPointInEnvelope(Point point)
        {
            //垂直情况
            if (Envelope.XMin == Envelope.XMax &&
                point.Y < Envelope.YMax && point.Y > Envelope.YMin)
                return true;
            //水平情况
            if (Envelope.YMin == Envelope.YMax &&
                point.X < Envelope.XMax && point.X > Envelope.XMin)
                return true;
            //一般情况
            if (point.X < Envelope.XMax && point.X > Envelope.XMin &&
                point.Y < Envelope.YMax && point.Y > Envelope.YMin)
                return true;
            return false;
        }
        #endregion
    }
}
